#ifndef MODEL_H
#define MODEL_H

#include <string>
#include <IShader.h>
#include <vector>
#include <list>
#include <assimp/scene.h>
#include <Cache.h>
#include <memory>
#include "Mesh.h"
#include "ModelAnimation.h"

class Model
{
public:
    explicit Model(const std::string& path);
    void Draw(const gl::IShader& shader) const;
    void Play(const std::string& animName, uint32_t frame);
    void SetModelMatrix(const glm::mat4& mMat);

private:
    std::string filePath;
    std::list<Mesh> meshes;
    std::string directory;
    std::unordered_map<std::string, uint32_t> boneNameIndex;
    Cache<std::string, std::shared_ptr<ModelAnimation>> cachedAnim;
    std::unordered_map<uint32_t, glm::mat4> boneOffsetCache;
    glm::mat4 animGlobalInverseT{};

    void LoadModel(const std::string& path);
    Texture LoadMaterialTextures(const aiScene* scene, aiMaterial* material, aiTextureType type,const std::string& typeName);
    void LoadAnimations(const aiScene* scene);
    void LoadMeshes(const aiScene* scene);

    void BoneTransform(const aiNode* root, aiAnimation* anim, float timeInMs, std::vector<glm::mat4> &transforms);
    void NodeAnimInner(aiAnimation* anim, float animationTime, const aiNode *node, const glm::mat4 &parentTransform, std::vector<glm::mat4>& transforms);
    static const aiNodeAnim *FindNodeAnim(const aiAnimation *animation, const std::string &nodeName);

};


#endif //MODEL_H
